home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 (Walnut Creek) / Aminet - June 1993 [Walnut Creek].iso / usenet / sources / volume89 / aplictns / graph.7 < prev    next >
Internet Message Format  |  1989-11-13  |  58KB

  1. Path: xanth!lll-winken!ctrsol!gem.mps.ohio-state.edu!brutus.cs.uiuc.edu!wuarchive!texbell!texsun!newstop!sun!swap!page
  2. From: page%swap@Sun.COM (Bob Page)
  3. Newsgroups: comp.sources.amiga
  4. Subject: v89i210:  graph - plot mathematical functions, Part07/07
  5. Message-ID: <127788@sun.Eng.Sun.COM>
  6. Date: 13 Nov 89 02:33:00 GMT
  7. Sender: news@sun.Eng.Sun.COM
  8. Lines: 1795
  9. Approved: page@sun.com
  10.  
  11. Submitted-by: dg3i+@andrew.cmu.edu (David Gay)
  12. Posting-number: Volume 89, Issue 210
  13. Archive-name: applications/graph.7
  14.  
  15. # This is a shell archive.
  16. # Remove anything above and including the cut line.
  17. # Then run the rest of the file through 'sh'.
  18. # Unpacked files will be owned by you and have default permissions.
  19. #----cut here-----cut here-----cut here-----cut here----#
  20. #!/bin/sh
  21. # shar: SHell ARchive
  22. # Run the following text through 'sh' to create:
  23. #    uio.c
  24. #    uio.h
  25. #    x_y.c
  26. # This is archive 7 of a 7-part kit.
  27. # This archive created: Sun Nov 12 18:23:32 1989
  28. echo "extracting uio.c"
  29. sed 's/^X//' << \SHAR_EOF > uio.c
  30. X/*
  31. X *                 GRAPH, Version 1.00 - 4 August 1989
  32. X *
  33. X *            Copyright 1989, David Gay. All Rights Reserved.
  34. X *            This software is freely redistrubatable.
  35. X */
  36. X
  37. X/* User interface routines */
  38. X
  39. X#include <exec/types.h>
  40. X#include <exec/interrupts.h>
  41. X#include <exec/ports.h>
  42. X#include <exec/io.h>
  43. X#include <exec/interrupts.h>
  44. X#include <devices/input.h>
  45. X#include <devices/inputevent.h>
  46. X#define INTUITIONPRIVATE
  47. X#include <intuition/intuitionbase.h>
  48. X#include <intuition/intuition.h>
  49. X#include <graphics/text.h>
  50. X#include <libraries/diskfont.h>
  51. X#include "libraries/arpbase.h"
  52. X#include <math.h>
  53. X#include <stdio.h>
  54. X#include <string.h>
  55. X#include <assert.h>
  56. X#include <dos.h>
  57. X#include <stdarg.h>
  58. X#include <ctype.h>
  59. X
  60. X#include "uio.h"
  61. X#include "graph.h"
  62. X#include "grph.h"
  63. X#include "list.h"
  64. X#include "object.h"
  65. X#include "user/gadgets.h"
  66. X#include "tracker.h"
  67. X
  68. X#include <proto/exec.h>
  69. X#include <proto/intuition.h>
  70. X#include <proto/graphics.h>
  71. X#include <proto/diskfont.h>
  72. X#define NODOS
  73. X#include "proto/arp.h"
  74. X
  75. X#define DEFAVAILSIZE 2048 /* Default space reserved for AvailFonts */
  76. X#define ARROW 42 /* Identifier of arrow gadget */
  77. X#define CROSS 666 /* Identifer of cross gadget */
  78. X
  79. Xstruct fnode /* font node */
  80. X{
  81. X    tnode node;
  82. X    char name[FONTLEN];
  83. X};
  84. X
  85. Xtlist flist;
  86. X
  87. Xextern struct IntuitionBase *IntuitionBase;
  88. X
  89. X/* Default graph window */
  90. Xstatic struct NewWindow graph_win = {
  91. X    0, 0,
  92. X    640, 200,
  93. X    -1, -1,
  94. X    RAWKEY | REFRESHWINDOW | CLOSEWINDOW | MENUPICK | GADGETDOWN | GADGETUP | R
  95. XEQCLEAR | REQSET | MOUSEBUTTONS | MOUSEMOVE,
  96. X    WINDOWSIZING | WINDOWDRAG | WINDOWDEPTH | WINDOWCLOSE | SIMPLE_REFRESH | AC
  97. XTIVATE,
  98. X    NULL,
  99. X    NULL,
  100. X    "Graph",
  101. X    NULL,
  102. X    NULL,
  103. X    85, 60,
  104. X    -1, -1,
  105. X    WBENCHSCREEN
  106. X};
  107. X
  108. X/* The two icon images */
  109. Xstatic UWORD chip arrow_data[] = {
  110. X    0x7fff, 0x7fff, 0x601f, 0x603f, 0x607f, 0x607f, 0x603f, 0x661f, 0x6f0f, 0x7
  111. Xf87, 0x7fc3, 0x7fe3, 0x7fff,
  112. X    0x0000, 0x0000, 0x1fe0, 0x1fc0, 0x1f80, 0x1f80, 0x1fc0, 0x19e0, 0x10f0, 0x0
  113. X078, 0x003c, 0x001c, 0x0000
  114. X};
  115. X
  116. Xstatic struct Image arrow_image = {
  117. X    -1, 0, 16, 13, 2,
  118. X    arrow_data,
  119. X    3, 0
  120. X};
  121. X
  122. Xstatic struct Gadget arrow = {
  123. X    NULL,
  124. X    -18, 18, 15, 13,
  125. X    GADGHCOMP | GADGIMAGE | GRELRIGHT,
  126. X    RELVERIFY | RIGHTBORDER | TOGGLESELECT,
  127. X    BOOLGADGET,
  128. X    (APTR)&arrow_image, NULL, NULL,
  129. X    2,
  130. X    NULL,
  131. X    ARROW
  132. X};
  133. X
  134. Xstatic UWORD chip cross_data[] = {
  135. X    0x7fff, 0x7f7f, 0x7f7f, 0x7f7f, 0x7f7f, 0x7e3f, 0x4081, 0x7e3f, 0x7f7f, 0x7
  136. Xf7f, 0x7f7f, 0x7f7f, 0x7fff,
  137. X    0x0000, 0x0080, 0x0080, 0x0080, 0x0080, 0x01c0, 0x3f7e, 0x01c0, 0x0080, 0x0
  138. X080, 0x0080, 0x0080, 0x0000
  139. X};
  140. X
  141. Xstatic struct Image cross_image = {
  142. X    -1, 0, 16, 13, 2,
  143. X    cross_data,
  144. X    3, 0
  145. X};
  146. X
  147. Xstatic struct Gadget cross = {
  148. X    NULL,
  149. X    -18, 36, 15, 13,
  150. X    GADGHCOMP | GADGIMAGE | GRELRIGHT | SELECTED,
  151. X    RELVERIFY | RIGHTBORDER | TOGGLESELECT,
  152. X    BOOLGADGET,
  153. X    (APTR)&cross_image, NULL, NULL,
  154. X    1,
  155. X    NULL,
  156. X    CROSS
  157. X};
  158. X
  159. Xstatic struct Memory *abort_mem; /* for abort requester */
  160. X
  161. Xstatic struct TextAttr alert_attr = { "topaz.font", 8 };
  162. Xstatic struct TextFont *alert_font;
  163. X
  164. Xstatic struct Task *me;
  165. Xstatic struct MsgPort *inputDevPort; /* for input device */
  166. Xstatic struct IOStdReq *inputRequestBlock;
  167. Xstatic struct Interrupt handlerStuff;
  168. Xstatic int inputOpen;
  169. X
  170. Xstatic long window_sigs;  /* Combined sigs of all windows */
  171. X
  172. Xstatic struct TextAttr font = { "topaz.font", 8 }; /* font for menus, requester
  173. Xs, etc */
  174. Xstatic struct Requester *req;    /* Current requester */
  175. Xstatic int ok;                   /* Value of last GadgetID */
  176. Xstatic short reqdone;            /* Req must go away. Don't activate next str g
  177. Xadget */
  178. Xstatic gadgevent *gadgethandler; /* Handler for gadget events */
  179. X
  180. X/* Add .font extension to fname (assumed of size FONTLEN) */
  181. Xchar *addfont(char *fname)
  182. X{
  183. X    return strncat(fname, ".font", FONTLEN - 1 - strlen(fname));
  184. X}
  185. X
  186. X/* Removes .font extension if present */
  187. Xchar *remfont(char *fname)
  188. X{
  189. X    int l = strlen(fname);
  190. X
  191. X    if (l >= 5 && strcmp(&fname[l - 5], ".font") == 0) fname[l - 5] = '\0';
  192. X
  193. X    return fname;
  194. X}
  195. X
  196. X/* Make a list of font names, one entry per font. Sizes, etc ignored. */
  197. Xint make_font_list(void)
  198. X{
  199. X    int ok = FALSE;
  200. X    char *abuf;
  201. X
  202. X    new_list(&flist);
  203. X    if (abuf = AllocMem(DEFAVAILSIZE, 0L)) /* Alloc default avail buffer */
  204. X    {
  205. X        int needs = AvailFonts(abuf, DEFAVAILSIZE, AFF_MEMORY | AFF_DISK);
  206. X
  207. X        ok = TRUE;
  208. X        if (needs != 0) /* Need a bigger buffer */
  209. X        {
  210. X            FreeMem(abuf, DEFAVAILSIZE);
  211. X            if (abuf = AllocMem(DEFAVAILSIZE + needs, 0L))
  212. X                if (AvailFonts(abuf, DEFAVAILSIZE + needs, AFF_MEMORY | AFF_DIS
  213. XK))
  214. X                    ok = FALSE; /* Definite failure */
  215. X        }
  216. X        if (ok) /* Construct font list */
  217. X        {
  218. X            struct AvailFontsHeader *hdr = (struct AvailFontsHeader *)abuf;
  219. X            struct AvailFonts *fl = (struct AvailFonts *)(hdr + 1);
  220. X            int i;
  221. X
  222. X            /* Add font entries to sorted list, by name. Duplicate entries remo
  223. Xved */
  224. X            for (i = hdr->afh_NumEntries; i > 0; i--, fl++)
  225. X            {
  226. X                struct fnode *scan;
  227. X                char *name = fl->af_Attr.ta_Name;
  228. X                int cmp = -1;
  229. X
  230. X                remfont(name); /* remove extension */
  231. X
  232. X                /* Find insertion position */
  233. X                for (scan = first(&flist); succ(scan) && (cmp = strcmp(name, sc
  234. Xan->name)) > 0; scan = succ(scan))
  235. X                    ;
  236. X                if (cmp != 0) /* Not already present, add to list */
  237. X                {
  238. X                    struct fnode *n = alloc_node(sizeof(struct fnode));
  239. X
  240. X                    if (!n)
  241. X                    {
  242. X                        ok = FALSE;
  243. X                        break;
  244. X                    }
  245. X                    n->node.ln_Name = n->name;
  246. X                    n->name[FONTLEN - 1] = '\0';
  247. X                    strncpy(n->name, name, FONTLEN - 1);
  248. X
  249. X                    /* Add at correct position */
  250. X                    insert(&flist, n, scan->node.ln_Pred);
  251. X                }
  252. X            }
  253. X            if (!ok)
  254. X            {
  255. X                free_list((list *)&flist, sizeof(struct fnode));
  256. X                new_list(&flist);
  257. X            }
  258. X        }
  259. X        FreeMem(abuf, DEFAVAILSIZE + needs);
  260. X    }
  261. X    if (!ok) nomem(NULL);
  262. X    return ok;
  263. X}
  264. X
  265. X
  266. X/* Implement mutual exclude seeing Intuition is lazy */
  267. X/* (for border gadgets)                              */
  268. X/* ------------------------------------------------- */
  269. Xstatic void MutualExclude(struct Gadget *us, struct Gadget *gadg, struct Window
  270. X *win)
  271. X{
  272. X    register int i;
  273. X    register struct Gadget *gp;
  274. X    register LONG mutex = us->MutualExclude;
  275. X    UWORD pos;
  276. X
  277. X    /* scan gadget list */
  278. X    for (i = 1, gp = gadg; gp && i != 0; i <<= 1, gp = gp->NextGadget)
  279. X        if (i & mutex)
  280. X        {
  281. X            pos = RemoveGadget(win, gp);
  282. X            gp->Flags &= ~SELECTED; /* unselect */
  283. X            AddGadget(win, gp, pos);
  284. X        }
  285. X    pos = RemoveGadget(win, us);
  286. X    us->Flags |= SELECTED;
  287. X    AddGadget(win, us, pos);
  288. X
  289. X    RefreshWindowFrame(win); /* This works for border gadgets */
  290. X}
  291. X
  292. X/* Implement mutual exclude seeing Intuition is lazy */
  293. X/* (for requester gadgets)                           */
  294. Xstatic void MutEx(struct Gadget *us, struct Requester *req)
  295. X{
  296. X    register int nb = 0, doneus = FALSE;
  297. X    register struct Gadget *gp, *first = NULL;
  298. X    register LONG mutex = us->MutualExclude;
  299. X    UWORD pos;
  300. X
  301. X    /* scan gadget list */
  302. X    for (gp = req->ReqGadget; gp && (mutex != 0 || !doneus); mutex >>= 1, gp =
  303. Xgp->NextGadget)
  304. X    {
  305. X        if ((mutex & 1) || (doneus = gp == us))
  306. X        {
  307. X            if (!first) first = gp;
  308. X            pos = RemoveGList(req->RWindow, gp, 1);
  309. X            if (gp == us)
  310. X                gp->Flags |= SELECTED;  /* select */
  311. X            else
  312. X                gp->Flags &= ~SELECTED; /* unselect */
  313. X            AddGList(req->RWindow, gp, pos, 1, req);
  314. X        }
  315. X        if (first) nb++;
  316. X    }
  317. X    if (first) RefreshGList(first, req->RWindow, req, nb);
  318. X}
  319. X
  320. X/* Display requester, & handle everything until it goes away */
  321. Xint DoRequest(struct Requester *r, struct graph *g, gadgevent *handle)
  322. X{
  323. X    r->Flags |= NOISYREQ; /* We want keystrokes */
  324. X
  325. X    ok = FALSE;
  326. X    if (Request(r, g->io.win))
  327. X    {
  328. X        /* setup vital info */
  329. X        gadgethandler = handle;
  330. X        req = r;
  331. X        reqdone = FALSE;
  332. X        while (next_command().command != reqgone) ; /* Wait till it leaves */
  333. X        req = NULL; /* No req. present */
  334. X        gadgethandler = NULL;
  335. X    }
  336. X    return ok;
  337. X}
  338. X
  339. X/* Find first string gadget */
  340. Xstatic struct Gadget *NextText(struct Gadget *look)
  341. X{
  342. X    while (look && (look->GadgetType & ~GADGETTYPE) != STRGADGET) look = look->
  343. XNextGadget;
  344. X    return look;
  345. X}
  346. X
  347. X/* Default gadget handler, activates string gadgets in sequence & handles
  348. X   mutual exclude. Will normally be called by custom handlers if they don't
  349. X   have anything special to do.
  350. X   Returens the new value of ok */
  351. Xint std_ghandler(struct Gadget *gg, ULONG class, struct Requester *req, struct
  352. Xgraph *g)
  353. X{
  354. X    if ((gg->GadgetType & ~GADGETTYPE) == STRGADGET && !reqdone) /* Activate ne
  355. Xxt one */
  356. X    {
  357. X        struct Gadget *ng = NextText(gg->NextGadget);
  358. X        if (!ng) ng = NextText(req->ReqGadget);
  359. X        if (ng) ActivateGadget(ng, req->RWindow, req);
  360. X    }
  361. X    else if (gg->MutualExclude != 0) MutEx(gg, req);
  362. X
  363. X    return gg->GadgetID != 0;
  364. X}
  365. X
  366. X/* Insert ins in front of into, checking for string overflow
  367. X   ( sizeof(into)=maxlen ) */
  368. Xstatic char *strinsert(char *into, char *ins, int maxlen)
  369. X{
  370. X    int delta = strlen(ins);
  371. X    int start = strlen(into);
  372. X    int i;
  373. X
  374. X    if (start + delta >= maxlen) start = maxlen - delta - 1;
  375. X
  376. X    for (i = start - 1; i >= 0; i--) into[i + delta] = into[i];
  377. X    into[start + delta] = '\0';
  378. X    memcpy(into, ins, delta);
  379. X
  380. X    return into;
  381. X}
  382. X
  383. X/* Convert a lock to a path, store in to (maxlen chars long) */
  384. Xstatic char *pathstr(char *to, long l, int maxlen)
  385. X{
  386. X    long tl;
  387. X    int notfirst = FALSE;
  388. X    struct FileInfoBlock *fib = (struct FileInfoBlock *)AllocMem(sizeof(struct
  389. XFileInfoBlock), 0);
  390. X
  391. X    if (!fib) return(NULL);
  392. X    to[0] = '\0';
  393. X
  394. X    do {
  395. X        if (!Examine(l, fib))
  396. X        {
  397. X            to = NULL;
  398. X            goto error;
  399. X        }
  400. X        if (fib->fib_DirEntryType > 0) strinsert(to, "/", maxlen);
  401. X        /* Is this still necessary ? */
  402. X        if (fib->fib_FileName[0] == '\0') strinsert(to, "RAM", maxlen);
  403. X        else strinsert(to, fib->fib_FileName, maxlen);
  404. X        tl = l;
  405. X        l = ParentDir(l);
  406. X        if (notfirst) UnLock(tl); /* Release allocated locks */
  407. X        notfirst = TRUE;
  408. X    } while (l);
  409. X
  410. X    *(strchr(to, '/')) = ':'; /* First name is disk name */
  411. X
  412. Xerror:
  413. X    FreeMem((char *)fib, sizeof(struct FileInfoBlock));
  414. X    return(to);
  415. X}
  416. X
  417. X/* Request a file from the user (save in file), return TRUE if OK,
  418. X   FALSE if cancelled or failed. Currently uses arp file requester. */
  419. Xint getfile(char *file, char *msg)
  420. X{
  421. X    static char directory[DSIZE + 1];
  422. X    static struct FileRequester FR;
  423. X    char filename[FCHARS + 1];
  424. X
  425. X    filename[0] = '\0';
  426. X    FR.fr_Hail = msg;
  427. X    FR.fr_File = filename;
  428. X    FR.fr_Dir = directory;
  429. X
  430. X    if (FileRequest(&FR))
  431. X    {
  432. X        long lock = Lock(directory, SHARED_LOCK);
  433. X
  434. X        if (lock)
  435. X        {
  436. X            if (!pathstr(file, lock, FILELEN)) /* get dir path */
  437. X            {
  438. X                UnLock(lock);
  439. X                return FALSE;
  440. X            }
  441. X            strncat(file, filename, FILELEN - 1 - strlen(file));
  442. X
  443. X            UnLock(lock);
  444. X            return TRUE;
  445. X        }
  446. X        else
  447. X            alert(NULL, "Failed to lock directory", directory);
  448. X    }
  449. X    return FALSE;
  450. X}
  451. X
  452. X/* Setup an "abort" requester, in graph g with text msg (must be as long as max
  453. X message) */
  454. Xstruct Requester *abort_request(struct graph *g, char *msg)
  455. X{
  456. X    int len = strlen(msg);
  457. X    struct Requester *req;
  458. X    struct Gadget *gl = NULL;
  459. X    int height, width;
  460. X    static struct Gadget text = {
  461. X        NULL,
  462. X        10, 10, 1, 1,
  463. X        GADGHNONE, 0L, BOOLGADGET | REQGADGET
  464. X    };
  465. X
  466. X    /* Construct requester */
  467. X    height = 8 * 1 + 10 + 12 + 25;
  468. X    width = 8 * len + 2 * 10;
  469. X    if (width < 85) width = 85;
  470. X
  471. X    text.GadgetText = NULL;
  472. X    if ((abort_mem = NewMemory()) &&
  473. X        (req = InitReq(50, 15, width, height, abort_mem)) &&
  474. X        SetReqBorder(req, 1, abort_mem) &&
  475. X        AddBox(&gl, TRUE, "Stop!", 0, RELVERIFY, (width - 65) / 2, height - 25,
  476. X 65, 15, FALSE, abort_mem) &&
  477. X        AddIntuiText(&text.GadgetText, msg, 0, 0, abort_mem))
  478. X    {
  479. X        SetReqGadgets(req, gl);
  480. X        text.NextGadget = req->ReqGadget;
  481. X        req->ReqGadget = &text;
  482. X        if (!Request(req, g->io.win)) req = NULL; /* display req */
  483. X    }
  484. X    else
  485. X        req = NULL;
  486. X
  487. X    if (!req) Free(abort_mem);
  488. X
  489. X    return req;
  490. X}
  491. X
  492. X/* Change abort requester message. msg must not be longer than the first msg */
  493. X     
  494. Xvoid set_abort_msg(struct Requester *req, char *msg)
  495. X{
  496. X    req->ReqGadget->GadgetText->IText = msg;
  497. X    RefreshGList(req->ReqGadget, req->RWindow, req, 1);
  498. X}
  499. X
  500. X/* Clear abort requester */
  501. Xvoid end_abort_request(struct Requester *req)
  502. X{
  503. X    EndRequest(req, req->RWindow);
  504. X    Free(abort_mem);
  505. X}
  506. X
  507. X/* Has the user asked for an abort ? */
  508. Xint aborted(struct Requester *req)
  509. X{
  510. X    int abort = FALSE;
  511. X    struct IntuiMessage *msg;
  512. X
  513. X    while (msg = (struct IntuiMessage *)GetMsg(req->RWindow->UserPort))
  514. X    {
  515. X        ULONG class = msg->Class;
  516. X
  517. X        ReplyMsg((struct Message *)msg);
  518. X
  519. X        if (class == REFRESHWINDOW) /* Ignore refreshes at this time */
  520. X        {
  521. X            BeginRefresh(req->RWindow);
  522. X            EndRefresh(req->RWindow, TRUE);
  523. X        }
  524. X        else if (class == GADGETUP) abort = TRUE;
  525. X    }
  526. X    return abort;
  527. X}
  528. X
  529. X/* Display a message in graph g. You pass as many string as you want, followed
  530. X   by (char *)NULL. This will try very hard to actually display it, calling
  531. X   alert with the first two strings if it fails. */
  532. Xvoid message(struct graph *g, ...)
  533. X{
  534. X    int nb, len;
  535. X    va_list msgs;
  536. X    char *scan;
  537. X    struct Memory *m;
  538. X    struct Requester *req;
  539. X    struct Gadget *gl = NULL;
  540. X    int height, width;
  541. X    int ok = FALSE;
  542. X
  543. X    /* Find number of lines and maxmimum length */
  544. X    nb = 0; len = 0;
  545. X    va_start(msgs, g);
  546. X    while (scan = va_arg(msgs, char *))
  547. X    {
  548. X        int nl = strlen(scan);
  549. X
  550. X        nb++;
  551. X        if (nl > len) len = nl;
  552. X    }
  553. X    va_end(msgs);
  554. X
  555. X    /* Construct requester */
  556. X    height = 8 * nb + 10 + 12 + 25;
  557. X    width = 8 * len + 2 * 10;
  558. X    if (width < 85) width = 85;
  559. X
  560. X    if ((m = NewMemory()) &&
  561. X        (req = InitReq(50, 15, width, height, m)) &&
  562. X        SetReqBorder(req, 1, m) &&
  563. X        AddBox(&gl, TRUE, "Ok", 0, RELVERIFY | ENDGADGET, (width - 65) / 2, hei
  564. Xght - 25, 65, 15, FALSE, m))
  565. X    {
  566. X        int y = 10 - 8;
  567. X
  568. X        ok = TRUE;
  569. X        SetReqGadgets(req, gl);
  570. X
  571. X        /* Add message strings */
  572. X        va_start(msgs, g);
  573. X        while (ok && (scan = va_arg(msgs, char *)))
  574. X            ok = ok && AddIntuiText(&req->ReqText, scan, 10, (y += 8), m);
  575. X        va_end(msgs);
  576. X
  577. X        /* You'll have a surprise if you press Amiga-B ... */
  578. X        if (ok && g) ok = DoRequest(req, g, std_ghandler);
  579. X    }
  580. X    Free(m);
  581. X    if (!ok || !g) /* call alert */
  582. X    {
  583. X        va_start(msgs, g);
  584. X        if (nb == 1)
  585. X            alert(g ? g->io.win : NULL, va_arg(msgs, char *), NULL);
  586. X        else if (nb >= 2)
  587. X        {
  588. X            char *m1 = va_arg(msgs, char *);
  589. X            char *m2 = va_arg(msgs, char *);
  590. X
  591. X            alert(g ? g->io.win : NULL, m1, m2);
  592. X        }
  593. X    }
  594. X}
  595. X
  596. X/* Display a two line auto request. Doesn't alloc any resources */
  597. Xvoid alert(struct Window *win, char *msg1, char *msg2)
  598. X{
  599. X    struct IntuiText text1, text2, negative;
  600. X    const static struct IntuiText template = {
  601. X        0, 1, JAM1,
  602. X        8, 0,
  603. X        &alert_attr
  604. X    };
  605. X    int width, height;
  606. X    int ysize = alert_font ? alert_font->tf_YSize : 8;
  607. X
  608. X    text1 = text2 = negative = template;
  609. X    text1.TopEdge = 8;
  610. X    text1.IText = msg1;
  611. X    width = IntuiTextLength(&text1) + 20;
  612. X    height = 37 + 2 * ysize;
  613. X    if (msg2 != NULL)
  614. X    {
  615. X        int w;
  616. X
  617. X        text1.NextText = &text2;
  618. X        text2.TopEdge = text1.TopEdge + ysize;
  619. X        text2.IText = msg2;
  620. X
  621. X        height += ysize;
  622. X        w = IntuiTextLength(&text2) + 20;
  623. X        if (w > width) width = w;
  624. X    }
  625. X    negative.LeftEdge = 6;
  626. X    negative.TopEdge = 4;
  627. X    negative.IText = "Ok";
  628. X
  629. X    AutoRequest(win, &text1, NULL, &negative, 0L, 0L, width, height);
  630. X}
  631. X
  632. X/* Easy no mem requester */
  633. Xvoid nomem(struct Window *win)
  634. X{
  635. X    alert(win, "No memory !", NULL);
  636. X}
  637. X
  638. X/* Return next menu selection that is a command (in graph g).
  639. X   *choice is the item number of the next menu selection */
  640. Xstatic struct cmd process(UWORD *choice, struct graph *g)
  641. X{
  642. X    struct MenuItem *item;
  643. X    UWORD itemnb, subnb;
  644. X    struct cmd cmd;
  645. X    struct pos *rect = (struct pos *)g->s.current;
  646. X
  647. X    /* Prepare command */
  648. X    cmd.command = none;
  649. X    cmd.g = g;
  650. X
  651. X    /* Try & find a command */
  652. X    while (cmd.command == none && *choice != MENUNULL)
  653. X    {
  654. X        item = ItemAddress(g->io.menu, *choice);
  655. X        itemnb = ITEMNUM(*choice);
  656. X        subnb = SUBNUM(*choice);
  657. X
  658. X        /* Rem: illegal choices are disabled ==> no checking here */
  659. X        switch (MENUNUM(*choice)) {
  660. X            case 0 : switch (itemnb) { /* Project */
  661. X                case 0 : /* New Graph */
  662. X                    cmd.command = _new_graph;
  663. X                    break;
  664. X                case 1 : /* Delete Graph */
  665. X                    cmd.command = close;
  666. X                    break;
  667. X                case 2 : /* Load Graph */
  668. X                    cmd.command = _load_graph;
  669. X                    break;
  670. X                case 3 : /* Save Graph */
  671. X                    cmd.command = _save_graph;
  672. X                    break;
  673. X                case 4 : /* Output Graph */
  674. X                    switch (subnb)
  675. X                    {
  676. X                        case 0 : /* To Printer */
  677. X                            cmd.command = print_graph;
  678. X                            break;
  679. X                        case 1 : /* To Disk */
  680. X                            cmd.command = iff_graph;
  681. X                            break;
  682. X                    }
  683. X                    break;
  684. X                case 6 : /* Load Variables */
  685. X                    cmd.command = load_vars;
  686. X                    break;
  687. X                case 7 : /* Save Variables */
  688. X                    cmd.command = save_vars;
  689. X                    break;
  690. X                case 9 : /* Quit */
  691. X                    cmd.command = quit;
  692. X                    break;
  693. X                } break;
  694. X
  695. X            case 1 : switch (itemnb) { /* Graph */
  696. X                case 0 : /* Scale */
  697. X                    deselect(g);
  698. X                    cmd.command = limits;
  699. X                    break;
  700. X                case 1 : /* Axes */
  701. X                    deselect(g);
  702. X                    cmd.command = axes;
  703. X                    break;
  704. X                case 2 : /* Zoom */
  705. X                    cmd.command = zoom;
  706. X                    cmd.data.zoom_in.x0 = rect->x0;
  707. X                    cmd.data.zoom_in.y0 = rect->y0;
  708. X                    cmd.data.zoom_in.x1 = rect->x1;
  709. X                    cmd.data.zoom_in.y1 = rect->y1;
  710. X                    deselect(g);
  711. X                    break;
  712. X                case 3 : /* Zoom Out */
  713. X                    cmd.command = zoom_out;
  714. X                    cmd.data.zoom_out = 2.0;
  715. X                    break;
  716. X                case 4 : /* Center */
  717. X                    cmd.command = center;
  718. X                    cmd.data.pt.x = rect->x0;
  719. X                    cmd.data.pt.y = rect->y0;
  720. X                    deselect(g);
  721. X                    break;
  722. X                } break;
  723. X
  724. X            case 2 : switch (itemnb) { /* Add */
  725. X                case 0 : /* Function */
  726. X                    deselect(g);
  727. X                    cmd.command = add_function;
  728. X                    break;
  729. X                case 1 : /* Label */
  730. X                    cmd.command = add_label;
  731. X                    cmd.data.pt.x = rect->x0;
  732. X                    cmd.data.pt.y = rect->y0;
  733. X                    deselect(g);
  734. X                    break;
  735. X                } break;
  736. X
  737. X            case 3 : switch (itemnb) { /* Edit */
  738. X                case 0 : /* Variables */
  739. X                    cmd.command = edit_vars;
  740. X                    break;
  741. X                case 2 : /* Select function */
  742. X                    {   /* Processed locally */
  743. X                        struct object *o;
  744. X
  745. X                        if (o = choose_object(g, "Select"))
  746. X                        {
  747. X                            deselect(g);
  748. X                            select_object(g, o);
  749. X                        }
  750. X                    }
  751. X                    break;
  752. X                case 3 : /* Deselect */
  753. X                    /* Processed locally */
  754. X                    deselect(g);
  755. X                    break;
  756. X                case 5 : /* Edit */
  757. X                    cmd.data.o = g->s.current;
  758. X                    cmd.command = edit;
  759. X                    break;
  760. X                case 6 : /* Improve */
  761. X                    cmd.data.f = g->s.current;
  762. X                    cmd.command = improve;
  763. X                    break;
  764. X                case 7 : /* Delete */
  765. X                    cmd.data.o = g->s.current;
  766. X                    cmd.command = del_object;
  767. X                    break;
  768. X                } break;
  769. X        }
  770. X        *choice = item->NextSelect;
  771. X        *choice = MENUNULL;
  772. X    }
  773. X    return cmd;
  774. X}
  775. X
  776. X/* Return next command (in any graph) */
  777. Xstruct cmd next_command(void)
  778. X{
  779. X    struct cmd cmd;
  780. X    static int gone = FALSE;
  781. X
  782. X    cmd.command = none;
  783. X
  784. X    while (cmd.command == none) /* Wait for one */
  785. X    {
  786. X        struct graph *g;
  787. X
  788. X        /* Scan all graphs, checking for commands */
  789. X        for (g = first(&graph_list); cmd.command == none && succ(g); g = succ(g
  790. X))
  791. X        {
  792. X            int moved = FALSE;
  793. X            struct IntuiMessage *msg;
  794. X            WORD sx, sy;
  795. X
  796. X            cmd.g = g;
  797. X            /* Any pending menu selections ? */
  798. X            if (!req && g->io.nextmenu != MENUNULL) cmd = process(&g->io.nextme
  799. Xnu, g);
  800. X
  801. X            /* Check for messages on window */
  802. X            while (cmd.command == none && (msg = (struct IntuiMessage *)GetMsg(
  803. Xg->io.win->UserPort)))
  804. X            {
  805. X                /* Save interesting info */
  806. X                ULONG class = msg->Class;
  807. X                UWORD code = msg->Code;
  808. X                UWORD qualifier = msg->Qualifier;
  809. X                struct Gadget *gg = (struct Gadget *)msg->IAddress, *gadg;
  810. X
  811. X                sx = msg->MouseX; sy = msg->MouseY;
  812. X                ReplyMsg((struct Message *)msg);
  813. X
  814. X                if (class == MOUSEMOVE) /* Accumulate moves */
  815. X                    moved = TRUE;
  816. X                else
  817. X                {
  818. X                    if (moved) mouse_move(g, sx, sy); /* process any mouse move
  819. Xment */
  820. X                    moved = FALSE;
  821. X                    /* Most messages imply that the mouse button is released. M
  822. Xake sure that the program thinks so */
  823. X                    if (class != MOUSEBUTTONS && class != REFRESHWINDOW) mouse_
  824. Xup(g, sx, sy);
  825. X
  826. X                    switch (class)
  827. X                    {
  828. X                        /* Note that most messages are ignored while a
  829. X                           requester is up in *any* window */
  830. X
  831. X                        case RAWKEY:
  832. X                            /* Check for Amiga-V/B (Ok, Cancel shortcut) */
  833. X                            if (req && (qualifier & AMIGALEFT) && (code == KEYC
  834. XODE_V || code == KEYCODE_B))
  835. X                            {
  836. X                                ok = code == KEYCODE_V;
  837. X                                /* Never let this happen while a string gadget
  838. Xis active ... */
  839. X                                EndRequest(req, req->RWindow);
  840. X                            }
  841. X                            break;
  842. X                        case CLOSEWINDOW:
  843. X                            if (!req) cmd.command = close;
  844. X                            break;
  845. X                        case MENUPICK:
  846. X                            if (!req)
  847. X                            {
  848. X                                g->io.nextmenu = code;
  849. X                                cmd = process(&g->io.nextmenu, g);
  850. X                            }
  851. X                            break;
  852. X                        case REFRESHWINDOW:
  853. X                            {
  854. X                                int changed;
  855. X
  856. X                                /* Refresh partially only if size hasn't change
  857. Xd */
  858. X                                BeginRefresh(g->io.win);
  859. X                                changed = g->io.win->Width != g->io.oldwidth ||
  860. X g->io.win->Height != g->io.oldheight;
  861. X                                if (!changed) draw_graph(g, FALSE); /* No messa
  862. Xges during refresh !!! */
  863. X                                EndRefresh(g->io.win, TRUE);
  864. X                                if (changed)
  865. X                                {
  866. X                                    set_scale(g);
  867. X                                    draw_graph(g, TRUE);
  868. X                                }
  869. X                                /* Wait for refresh after requester's disappear
  870. Xance
  871. X                                   before signaling it */
  872. X                                if (gone)
  873. X                                {
  874. X                                    gone = FALSE;
  875. X                                    cmd.command = reqgone;
  876. X                                }
  877. X                            }
  878. X                            break;
  879. X                        case REQSET: /* Activate first string gadget */
  880. X                            gadg = NextText(req->ReqGadget);
  881. X                            if (gadg && !reqdone) ActivateGadget(gadg, g->io.wi
  882. Xn, req);
  883. X                            break;
  884. X                        case REQCLEAR:
  885. X                            /* Allow 1 refresh before signaling this. There is
  886. X                               probably a better way ! */
  887. X                            gone = TRUE;
  888. X                            break;
  889. X                        case GADGETUP: case GADGETDOWN:
  890. X                            /* Ack! Hack to avoid bug in string gadget activati
  891. Xon (V1.2-1.3) */
  892. X                            if (class == GADGETUP && (gg->GadgetType & STRGADGE
  893. XT) != 0 && IntuitionBase->LibNode.lib_Version <= 34) IntuitionBase->ActiveGadget
  894. X = NULL;
  895. X
  896. X                            /* Handle requester hgadgets */
  897. X                            if (gadgethandler) ok = gadgethandler(gg, class, re
  898. Xq, g);
  899. X                            else if (gg->GadgetID == ARROW || gg->GadgetID == C
  900. XROSS)
  901. X                            {   /* Select new mode */
  902. X                                MutualExclude(gg, g->io.gadgets, g->io.win);
  903. X                                set_mode(g, gg->GadgetID == ARROW);
  904. X                            }
  905. X                            break;
  906. X                        case MOUSEBUTTONS: /* Pass on to graph */
  907. X                            if (code == SELECTDOWN)
  908. X                                mouse_down(g, sx, sy);
  909. X                            else
  910. X                                mouse_up(g, sx, sy);
  911. X                            break;
  912. X                    }
  913. X                }
  914. X            }
  915. X            /* Handle any pending moves */
  916. X            if (moved) mouse_move(g, sx, sy);
  917. X        }
  918. X        /* Wait for something to happen */
  919. X        if (cmd.command == none) Wait(window_sigs);
  920. X    }
  921. X    return cmd;
  922. X}
  923. X
  924. X
  925. X/* Enable/Disable various menus */
  926. X
  927. Xvoid disable_rect_menus(struct graph *g)
  928. X{
  929. X    struct Window *win = g->io.win;
  930. X
  931. X    OffMenu(win, SHIFTMENU(1) | SHIFTITEM(2) | SHIFTSUB(NOSUB)); /* Zoom */
  932. X    OffMenu(win, SHIFTMENU(1) | SHIFTITEM(4) | SHIFTSUB(NOSUB)); /* Center */
  933. X    OffMenu(win, SHIFTMENU(2) | SHIFTITEM(1) | SHIFTSUB(NOSUB)); /* Label */
  934. X    OffMenu(win, SHIFTMENU(3) | SHIFTITEM(3) | SHIFTSUB(NOSUB)); /* Deselect */
  935. X     
  936. X}
  937. X
  938. Xvoid enable_rect_menus(struct graph *g)
  939. X{
  940. X    struct Window *win = g->io.win;
  941. X
  942. X    OnMenu(win, SHIFTMENU(1) | SHIFTITEM(2) | SHIFTSUB(NOSUB)); /* Zoom */
  943. X    OnMenu(win, SHIFTMENU(1) | SHIFTITEM(4) | SHIFTSUB(NOSUB)); /* Center */
  944. X    OnMenu(win, SHIFTMENU(2) | SHIFTITEM(1) | SHIFTSUB(NOSUB)); /* Label */
  945. X    OnMenu(win, SHIFTMENU(3) | SHIFTITEM(3) | SHIFTSUB(NOSUB)); /* Deselect */
  946. X}
  947. X
  948. Xvoid disable_object_menus(struct graph *g)
  949. X{
  950. X    struct Window *win = g->io.win;
  951. X
  952. X    OffMenu(win, SHIFTMENU(3) | SHIFTITEM(3) | SHIFTSUB(NOSUB)); /* Deselect */
  953. X     
  954. X    OffMenu(win, SHIFTMENU(3) | SHIFTITEM(5) | SHIFTSUB(NOSUB)); /* Edit */
  955. X    OffMenu(win, SHIFTMENU(3) | SHIFTITEM(6) | SHIFTSUB(NOSUB)); /* Improve */
  956. X    OffMenu(win, SHIFTMENU(3) | SHIFTITEM(7) | SHIFTSUB(NOSUB)); /* Delete */
  957. X}
  958. X
  959. Xvoid enable_object_menus(struct graph *g)
  960. X{
  961. X    struct Window *win = g->io.win;
  962. X
  963. X    OnMenu(win, SHIFTMENU(3) | SHIFTITEM(3) | SHIFTSUB(NOSUB)); /* Deselect */
  964. X    OnMenu(win, SHIFTMENU(3) | SHIFTITEM(5) | SHIFTSUB(NOSUB)); /* Edit */
  965. X    OnMenu(win, SHIFTMENU(3) | SHIFTITEM(6) | SHIFTSUB(NOSUB)); /* Improve */
  966. X    OnMenu(win, SHIFTMENU(3) | SHIFTITEM(7) | SHIFTSUB(NOSUB)); /* Delete */
  967. X}
  968. X
  969. X/* Convert double to nice string (must be of size NBLEN) */
  970. Xchar *double2str(char *to, double x)
  971. X{
  972. X    int l;
  973. X
  974. X    if (x == NOVAL) to[0] = '\0';
  975. X    else sprintf(to, "%-5.3g", x);
  976. X
  977. X    l = strlen(to);
  978. X    while (l > 0 && to[--l] == ' ') to[l] = '\0';
  979. X
  980. X    return to;
  981. X}
  982. X
  983. X
  984. X/* Convert string to double */
  985. Xdouble str2double(char *from)
  986. X{
  987. X    double x;
  988. X
  989. X    if (sscanf(from, "%lf", &x) != 1) x = NOVAL;
  990. X
  991. X    return x;
  992. X}
  993. X
  994. X/* convert x to a string (must be of size INTLEN) */
  995. Xchar *int2str(char *to, int x)
  996. X{
  997. X    if (x == INOVAL) to[0] = '\0';
  998. X    else sprintf(to, "%d", x);
  999. X
  1000. X    return to;
  1001. X}
  1002. X
  1003. X/* convert string to integer */
  1004. Xint str2int(char *from)
  1005. X{
  1006. X    int x;
  1007. X
  1008. X    if (sscanf(from, "%d", &x) != 1) x = INOVAL;
  1009. X
  1010. X    return x;
  1011. X}
  1012. X
  1013. X/* Removes leading & trailing blanks fron name. Returns name */
  1014. Xchar *strip(char *name)
  1015. X{
  1016. X    char *scan = name;
  1017. X
  1018. X    while (isspace(*scan)) scan++;
  1019. X
  1020. X    if (*scan)
  1021. X    {
  1022. X        char *copy = name;
  1023. X
  1024. X        while (*scan) *(copy++) = *(scan++);
  1025. X
  1026. X        while (isspace(*--copy))
  1027. X            ;
  1028. X        *(copy + 1) = '\0';
  1029. X    }
  1030. X    else
  1031. X        *name = '\0';
  1032. X
  1033. X    return name;
  1034. X}
  1035. X
  1036. X/* Hack to allow you to press Amiga-V/B even while entering a string in a
  1037. X   string requester */
  1038. Xstatic long __saveds __asm handle_ok_cancel(register __a0 struct InputEvent *ev
  1039. X, register __a1 void *dummy)
  1040. X{
  1041. X    struct InputEvent *ep, *laste;
  1042. X    static struct InputEvent retkey;
  1043. X
  1044. X    if (req)
  1045. X        /* run down the list of events to see if they pressed the magic key */
  1046. X        for (ep = ev, laste = NULL; ep != NULL; ep = ep->ie_NextEvent)
  1047. X        {
  1048. X            if (ep->ie_Class == IECLASS_RAWKEY && (ep->ie_Qualifier & AMIGALEFT
  1049. X) && (ep->ie_Code == KEYCODE_V || ep->ie_Code == KEYCODE_B) && IntuitionBase->Ac
  1050. XtiveWindow == req->RWindow)
  1051. X            {
  1052. X                reqdone = TRUE; /* The requester is going away */
  1053. X                /* Add an extra "return key" event */
  1054. X                retkey.ie_Class = IECLASS_RAWKEY;
  1055. X                retkey.ie_SubClass = 0;
  1056. X                retkey.ie_Code = 0x44; /* return key */
  1057. X                retkey.ie_Qualifier = 0;
  1058. X                retkey.ie_position = ep->ie_position;
  1059. X                retkey.ie_TimeStamp = ep->ie_TimeStamp;
  1060. X                retkey.ie_NextEvent = ep;
  1061. X                /* we can handle this event so take it off the chain */
  1062. X                if (laste == NULL)
  1063. X                    ev = &retkey;
  1064. X                else
  1065. X                    laste->ie_NextEvent = &retkey;
  1066. X                break;
  1067. X            }
  1068. X            else
  1069. X                laste = ep;
  1070. X        }
  1071. X
  1072. X   /* pass on the pointer to the event */
  1073. X   return (long)ev;
  1074. X}
  1075. X
  1076. X/* Create window, menus for a new graph */
  1077. Xint init_uio(struct graph *g)
  1078. X{
  1079. X    /* Create mode select gadgets */
  1080. X    struct Gadget *a = AllocMem(sizeof(struct Gadget), 0L);
  1081. X    struct Gadget *c = AllocMem(sizeof(struct Gadget), 0L);
  1082. X
  1083. X    ModSys(0, 1, JAM2, &font);
  1084. X    if (a && c)
  1085. X    {
  1086. X        struct Menu *ml = NULL, *project, *edit, *add, *graph;
  1087. X        struct MenuItem *print;
  1088. X
  1089. X        *a = arrow;
  1090. X        *c = cross;
  1091. X        a->NextGadget = c;
  1092. X        g->io.gadgets = graph_win.FirstGadget = a;
  1093. X        g->io.mem = NULL;
  1094. X
  1095. X        /* Create window & menus */
  1096. X        if (g->io.win = OpenWindow(&graph_win))
  1097. X            if ((g->io.mem = NewMemory()) &&
  1098. X                (project = AddMenu(&ml, NULL, "Project", MENUENABLED, g->io.mem
  1099. X)) &&
  1100. X                    AddItem(project, "New Graph", ITEMENABLED | HIGHCOMP, 0, 'N
  1101. X', FALSE, g->io.mem) &&
  1102. X                    AddItem(project, "Delete Graph", ITEMENABLED | HIGHCOMP, 0,
  1103. X 0, FALSE, g->io.mem) &&
  1104. X                    AddItem(project, "Load Graph...", ITEMENABLED | HIGHCOMP, 0
  1105. X, 'O', FALSE, g->io.mem) &&
  1106. X                    AddItem(project, "Save Graph...", ITEMENABLED | HIGHCOMP, 0
  1107. X, 'S', FALSE, g->io.mem) &&
  1108. X                    (print = AddItem(project, "Output Graph", ITEMENABLED | HIG
  1109. XHCOMP, 0, 0, TRUE, g->io.mem)) &&
  1110. X                        AddSub(print, "To Printer", ITEMENABLED | HIGHCOMP, 0,
  1111. X'P', g->io.mem) &&
  1112. X                        AddSub(print, "To Disk...", ITEMENABLED | HIGHCOMP, 0,
  1113. X0, g->io.mem) &&
  1114. X                    AddRule(project, g->io.mem) &&
  1115. X                    AddItem(project, "Load Variables...", ITEMENABLED | HIGHCOM
  1116. XP, 0, 0, FALSE, g->io.mem) &&
  1117. X                    AddItem(project, "Save Variables...", ITEMENABLED | HIGHCOM
  1118. XP, 0, 0, FALSE, g->io.mem) &&
  1119. X                    AddRule(project, g->io.mem) &&
  1120. X                    AddItem(project, "Quit", ITEMENABLED | HIGHCOMP, 0, 'Q', FA
  1121. XLSE, g->io.mem) &&
  1122. X                (graph = AddMenu(&ml, NULL, "Graph", MENUENABLED, g->io.mem)) &
  1123. X&
  1124. X                    AddItem(graph, "Scale...", ITEMENABLED | HIGHCOMP, 0, 'L',
  1125. XFALSE, g->io.mem) &&
  1126. X                    AddItem(graph, "Axes...", ITEMENABLED | HIGHCOMP, 0, 'X', F
  1127. XALSE, g->io.mem) &&
  1128. X                    AddItem(graph, "Zoom", ITEMENABLED | HIGHCOMP, 0, 'Z', FALS
  1129. XE, g->io.mem) &&
  1130. X                    AddItem(graph, "Zoom out", ITEMENABLED | HIGHCOMP, 0, 0, FA
  1131. XLSE, g->io.mem) &&
  1132. X                    AddItem(graph, "Centre", ITEMENABLED | HIGHCOMP, 0, 'C', FA
  1133. XLSE, g->io.mem) &&
  1134. X                (add = AddMenu(&ml, NULL, "Add", MENUENABLED, g->io.mem)) &&
  1135. X                    AddItem(add, "Function...", ITEMENABLED | HIGHCOMP, 0, 'F',
  1136. X FALSE, g->io.mem) &&
  1137. X                    AddItem(add, "Label...", ITEMENABLED | HIGHCOMP, 0, 0, FALS
  1138. XE, g->io.mem) &&
  1139. X                (edit = AddMenu(&ml, NULL, "Edit", MENUENABLED, g->io.mem)) &&
  1140. X                    AddItem(edit, "Variables...", ITEMENABLED | HIGHCOMP, 0, 'V
  1141. X', FALSE, g->io.mem) &&
  1142. X                    AddRule(edit, g->io.mem) &&
  1143. X                    AddItem(edit, "Select function...", ITEMENABLED | HIGHCOMP,
  1144. X 0, 0, FALSE, g->io.mem) &&
  1145. X                    AddItem(edit, "Deselect", ITEMENABLED | HIGHCOMP, 0, 0, FAL
  1146. XSE, g->io.mem) &&
  1147. X                    AddRule(edit, g->io.mem) &&
  1148. X                    AddItem(edit, "Edit...", ITEMENABLED | HIGHCOMP, 0, 'E', FA
  1149. XLSE, g->io.mem) &&
  1150. X                    AddItem(edit, "Improve", ITEMENABLED | HIGHCOMP, 0, 'I', FA
  1151. XLSE, g->io.mem) &&
  1152. X                    AddItem(edit, "Delete", ITEMENABLED | HIGHCOMP, 0, 0, FALSE
  1153. X, g->io.mem))
  1154. X            {
  1155. X                SetMenuStrip(g->io.win, ml);
  1156. X                g->io.menu = ml;
  1157. X                disable_rect_menus(g);
  1158. X                disable_object_menus(g);
  1159. X                /* Add signal bit */
  1160. X                window_sigs |= 1 << g->io.win->UserPort->mp_SigBit;
  1161. X
  1162. X                return TRUE; /* all done ok */
  1163. X            }
  1164. X            else
  1165. X            {
  1166. X                Free(g->io.mem);
  1167. X                CloseWindow(g->io.win);
  1168. X                alert(NULL, "No memory !", NULL);
  1169. X            }
  1170. X        else alert(NULL, "Couldn't open window", NULL);
  1171. X    }
  1172. X    else
  1173. X        alert(NULL, "No memory !", NULL);
  1174. X
  1175. X    if (a) FreeMem(a, sizeof(struct Gadget));
  1176. X    if (c) FreeMem(c, sizeof(struct Gadget));
  1177. X
  1178. X    return FALSE;
  1179. X}
  1180. X
  1181. X/* Close window, etc */
  1182. Xvoid cleanup_uio(struct graph *g)
  1183. X{
  1184. X    struct Gadget *gg, *next;
  1185. X
  1186. X    ClearMenuStrip(g->io.win);
  1187. X    CloseWindow(g->io.win);
  1188. X    Free(g->io.mem);
  1189. X    for (gg = g->io.gadgets; gg; gg = next)
  1190. X    {
  1191. X        next = gg->NextGadget;
  1192. X        FreeMem(gg, sizeof(struct Gadget));
  1193. X    }
  1194. X    /* Construct new signal list */
  1195. X    window_sigs = 0;
  1196. X    for (g = first(&graph_list); succ(g); g = succ(g))
  1197. X        window_sigs |= 1 << g->io.win->UserPort->mp_SigBit;
  1198. X}
  1199. X
  1200. X/* Global initialisation */
  1201. Xint init_user()
  1202. X{
  1203. X    if (!make_font_list()) return FALSE;
  1204. X    /* Open alert font */
  1205. X    alert_font = OpenFont(&alert_attr);
  1206. X
  1207. X    /* Install input handler */
  1208. X    me = FindTask(0);
  1209. X    inputDevPort = CreatePort(0,0);
  1210. X    if (inputDevPort)
  1211. X    {
  1212. X        if (inputRequestBlock = CreateStdIO(inputDevPort))
  1213. X        {
  1214. X
  1215. X            handlerStuff.is_Data = NULL;
  1216. X            handlerStuff.is_Code = (void *)handle_ok_cancel;
  1217. X            handlerStuff.is_Node.ln_Pri = 51;
  1218. X
  1219. X            if (OpenDevice("input.device", 0, inputRequestBlock, 0) == 0)
  1220. X            {
  1221. X                inputOpen = TRUE;
  1222. X                inputRequestBlock->io_Command = IND_ADDHANDLER;
  1223. X                inputRequestBlock->io_Data    = (APTR)&handlerStuff;
  1224. X
  1225. X                DoIO(inputRequestBlock);
  1226. X                return TRUE;
  1227. X            }
  1228. X        }
  1229. X    }
  1230. X    alert(NULL, "Couldn't install input handler", NULL);
  1231. X    return FALSE;
  1232. X}
  1233. X
  1234. X/* Global cleanup */
  1235. Xvoid cleanup_user()
  1236. X{
  1237. X    if (inputOpen)
  1238. X    {
  1239. X        inputRequestBlock->io_Command = IND_REMHANDLER;
  1240. X        inputRequestBlock->io_Data    = (APTR)&handlerStuff;
  1241. X        DoIO(inputRequestBlock);
  1242. X        CloseDevice(inputRequestBlock);
  1243. X    }
  1244. X    if (inputRequestBlock) DeleteStdIO(inputRequestBlock);
  1245. X    if (inputDevPort) DeletePort(inputDevPort);
  1246. X    free_list((list *)&flist, sizeof(struct fnode));
  1247. X}
  1248. X
  1249. SHAR_EOF
  1250. echo "extracting uio.h"
  1251. sed 's/^X//' << \SHAR_EOF > uio.h
  1252. X/*
  1253. X *                 GRAPH, Version 1.00 - 4 August 1989
  1254. X *
  1255. X *            Copyright 1989, David Gay. All Rights Reserved.
  1256. X *            This software is freely redistrubatable.
  1257. X */
  1258. X
  1259. X/* User interface routines (windows, menus, requesters, etc) */
  1260. X#ifndef UIO_H
  1261. X#define UIO_H
  1262. X
  1263. X#include "list.h"
  1264. X
  1265. X#define FONTLEN 30 /* font name length */
  1266. X#define NBLEN 25
  1267. X#define INTLEN 11
  1268. X
  1269. X/* A gadget handler routine, called for every gadget event when a requester is
  1270. Xpresent */
  1271. Xtypedef int gadgevent(struct Gadget *gadg, ULONG class, struct Requester *req,
  1272. Xstruct graph *g);
  1273. X
  1274. X/* All possible commands */
  1275. Xenum commands {none, reqgone, /* internal */
  1276. X               close, /* window closed */
  1277. X               /* menu functions */
  1278. X               _new_graph, _load_graph, _save_graph, print_graph, iff_graph, lo
  1279. Xad_vars, save_vars, quit,
  1280. X               limits, axes, zoom, zoom_out, center,
  1281. X               add_function, add_label,
  1282. X               edit, improve, del_object, edit_vars
  1283. X              };
  1284. X
  1285. X/* Description of selected command, union depends on command */
  1286. Xstruct cmd {
  1287. X    enum commands command;
  1288. X    struct graph *g;
  1289. X    union {
  1290. X        struct function *f;
  1291. X        struct object *o;
  1292. X        double zoom_out;
  1293. X        struct {
  1294. X            double x0, y0, x1, y1;
  1295. X        } zoom_in;
  1296. X        struct {
  1297. X            double x, y;
  1298. X        } pt;
  1299. X    } data;
  1300. X};
  1301. X
  1302. Xextern tlist flist;                 /* List of available font names */
  1303. X
  1304. Xint make_font_list(void);           /* (Re)make flist */
  1305. Xchar *addfont(char *fname);         /* Add/Remove ".font" from font names */
  1306. Xchar *remfont(char *fname);
  1307. X
  1308. X/* Display requester(in graph g), wait for it to leave */
  1309. X/* handle will be called for every gadget event */
  1310. Xint DoRequest(struct Requester *r, struct graph *g, gadgevent *handle);
  1311. X/* The default gadget handler (switches between text gadgets) */
  1312. Xint std_ghandler(struct Gadget *gg, ULONG class, struct Requester *req, struct
  1313. Xgraph *g);
  1314. Xint getfile(char *file, char *msg);                          /* File requester
  1315. X*/
  1316. Xstruct Requester *abort_request(struct graph *g, char *msg); /* Setup an abort
  1317. Xrequester */
  1318. Xvoid set_abort_msg(struct Requester *req, char *msg);        /* Change abort ms
  1319. Xg */
  1320. Xvoid end_abort_request(struct Requester *req);               /* Clear abort req
  1321. X */
  1322. Xint aborted(struct Requester *req);                          /* Did user abort
  1323. X? */
  1324. Xvoid message(struct graph *g, ...);                          /* Display a messa
  1325. Xge (in a graph) */
  1326. Xvoid alert(struct Window *win, char *msg1, char *msg2);      /* Use when no gra
  1327. Xph available */
  1328. Xvoid nomem(struct Window *win);                              /* Standard no mem
  1329. Xory alert */
  1330. X
  1331. Xstruct cmd next_command(void);      /* Return next selected command */
  1332. X
  1333. X/* String utility functions, convert numbers to strings */
  1334. Xchar *double2str(char *to, double x);
  1335. Xdouble str2double(char *from);
  1336. Xchar *int2str(char *to, int x);
  1337. Xint str2int(char *from);
  1338. Xchar *strip(char *name);            /* Strip leading & trailing blanks */
  1339. X
  1340. X/* Enable/Disable various menus */
  1341. Xvoid disable_rect_menus(struct graph *g);   /* Menus for 'pos' object */
  1342. Xvoid enable_rect_menus(struct graph *g);
  1343. Xvoid disable_object_menus(struct graph *g); /* For selected objects */
  1344. Xvoid enable_object_menus(struct graph *g);
  1345. X
  1346. Xint init_user(void);
  1347. Xvoid cleanup_user(void);
  1348. Xint init_uio(struct graph *g);      /* Setup/Cleanup interface for each graph *
  1349. X/
  1350. Xvoid cleanup_uio(struct graph *g);
  1351. X
  1352. X#endif
  1353. X
  1354. SHAR_EOF
  1355. echo "extracting x_y.c"
  1356. sed 's/^X//' << \SHAR_EOF > x_y.c
  1357. X/*
  1358. X *                 GRAPH, Version 1.00 - 4 August 1989
  1359. X *
  1360. X *            Copyright 1989, David Gay. All Rights Reserved.
  1361. X *            This software is freely redistrubatable.
  1362. X */
  1363. X
  1364. X#include <exec/types.h>
  1365. X#include <intuition/intuition.h>
  1366. X#include <graphics/text.h>
  1367. X#include <math.h>
  1368. X#include <string.h>
  1369. X
  1370. X#include "object.h"
  1371. X#include "object/function.h"
  1372. X#include "file.h"
  1373. X#include "graph.h"
  1374. X#include "uio.h"
  1375. X#include "coords.h"
  1376. X#include "list.h"
  1377. X#include "grph.h"
  1378. X#include "user/eval.h"
  1379. X#include "user/gadgets.h"
  1380. X#include "tracker.h"
  1381. X
  1382. X#include <proto/exec.h>
  1383. X#include <proto/intuition.h>
  1384. X#include <proto/graphics.h>
  1385. X
  1386. Xstruct x_y {
  1387. X    struct function f;
  1388. X    char x[EXPRLEN], y[EXPRLEN];
  1389. X    value x_t, y_t, dx, dy;
  1390. X};
  1391. X
  1392. Xstruct point_x_y {
  1393. X    point p;
  1394. X    double t;
  1395. X};
  1396. X
  1397. Xtypedef struct point_x_y point_x_y;
  1398. X
  1399. X/*-------------------------------------------------------------------------*/
  1400. X/*                        x_y class implementation                         */
  1401. X/*-------------------------------------------------------------------------*/
  1402. X
  1403. X/* Is the function displayable ? */
  1404. Xstatic int x_y_ok(const struct x_y *this)
  1405. X{
  1406. X    return this->f.min != NOVAL && this->f.max != NOVAL &&
  1407. X           this->f.min < this->f.max &&
  1408. X           (this->f.steps == INOVAL || this->f.steps >= 3);
  1409. X}
  1410. X
  1411. X/* Free resources */
  1412. Xstatic void destroy_x_y(struct x_y *this)
  1413. X{
  1414. X    free_var_list(&this->f.used);
  1415. X    if (this->f.calc) free_list(&this->f.pts, this->f.sizept);
  1416. X    this->f.calc = FALSE;
  1417. X    if (this->x_t) free_expr(this->x_t);
  1418. X    if (this->dx) free_expr(this->dx);
  1419. X    if (this->y_t) free_expr(this->y_t);
  1420. X    if (this->dy) free_expr(this->dy);
  1421. X    this->dx = this->dy = this->x_t = this->y_t = NULL;
  1422. X}
  1423. X
  1424. X/* Init dependant parts of function */
  1425. Xstatic int create_x_y(struct x_y *this)
  1426. X{
  1427. X    this->f.calc = FALSE;
  1428. X    this->f.var.name = this->f.vname;
  1429. X    this->x_t = compile(this->x);
  1430. X    if (eval_error != 0)
  1431. X    {
  1432. X        message(this->f.o.g, "Compilation error in x(t):", eval_messages[eval_e
  1433. Xrror], (char *)NULL);
  1434. X        return FALSE;
  1435. X    }
  1436. X    this->dx = differentiate(this->x_t, this->f.vname);
  1437. X    if (eval_error != NOT_DIFFERENTIABLE && eval_error != 0)
  1438. X    {
  1439. X        message(this->f.o.g, "Differentiation error (x):", eval_messages[eval_e
  1440. Xrror], (char *)NULL);
  1441. X        return FALSE;
  1442. X    }
  1443. X    this->y_t = compile(this->y);
  1444. X    if (eval_error != 0)
  1445. X    {
  1446. X        message(this->f.o.g, "Compilation error in y(t):", eval_messages[eval_e
  1447. Xrror], (char *)NULL);
  1448. X        return FALSE;
  1449. X    }
  1450. X    this->dy = differentiate(this->y_t, this->f.vname);
  1451. X    if (eval_error != NOT_DIFFERENTIABLE && eval_error != 0)
  1452. X    {
  1453. X        message(this->f.o.g, "Differentiation error(y):", eval_messages[eval_er
  1454. Xror], (char *)NULL);
  1455. X        return FALSE;
  1456. X    }
  1457. X    if (!make_var_list(this->x_t, &this->f.used) || !make_var_list(this->y_t, &
  1458. Xthis->f.used))
  1459. X        init_var_list(&this->f.used);
  1460. X    return TRUE;
  1461. X}
  1462. X
  1463. X/* Allow user to define function */
  1464. Xstatic int edit_x_y(struct x_y *this, struct Region **ref)
  1465. X{
  1466. X    struct Requester *req;
  1467. X    struct Memory *m;
  1468. X    struct Gadget *gl = NULL, *sd, *nd;
  1469. X    char from[NBLEN], to[NBLEN], steps[INTLEN], x[EXPRLEN], y[EXPRLEN], tname[V
  1470. XARLEN], colour[INTLEN];
  1471. X    int ret = FALSE;
  1472. X
  1473. X    *ref = NULL;
  1474. X
  1475. X    /* Create requester */
  1476. X    double2str(from, this->f.min);
  1477. X    double2str(to, this->f.max);
  1478. X    int2str(steps, this->f.steps);
  1479. X    int2str(colour, this->f.colour);
  1480. X    strcpy(x, this->x);
  1481. X    strcpy(y, this->y);
  1482. X    strcpy(tname, this->f.vname);
  1483. X
  1484. X    if ((m = NewMemory()) &&
  1485. X        (req = InitReq(50, 20, 255, 165, m)) &&
  1486. X        SetReqBorder(req, 1, m) &&
  1487. X        AddIntuiText(&req->ReqText, "Function", 95, 6, m) &&
  1488. X        AddText(&gl, 0, "x(", FALSE, tname, VARLEN, TRUE, 0, RELVERIFY, 25, 20,
  1489. X 24, 10, TRUE, m) &&
  1490. X        AddText(&gl, 0, ")=", FALSE, x, EXPRLEN, TRUE, 0, RELVERIFY, 81, 20, 16
  1491. X0, 10, TRUE, m) &&
  1492. X        AddText(&gl, 0, "y(   )=", FALSE, y, EXPRLEN, TRUE, 0, RELVERIFY, 81, 4
  1493. X0, 160, 10, TRUE, m) &&
  1494. X        AddText(&gl, 0, "from ", FALSE, from, NBLEN, TRUE, 0, RELVERIFY, 49, 60
  1495. X, 80, 10, TRUE, m) &&
  1496. X        AddText(&gl, 0, "to ", FALSE, to, NBLEN, TRUE, 0, RELVERIFY, 167, 60, 8
  1497. X0, 10, TRUE, m) &&
  1498. X        AddText(&gl, 0, "steps ", FALSE, steps, INTLEN, TRUE, 0, RELVERIFY, 57,
  1499. X 80, 32, 10, TRUE, m) &&
  1500. X        AddText(&gl, 0, "colour ", FALSE, colour, INTLEN, TRUE, 0, RELVERIFY, 1
  1501. X56, 80, 32, 10, TRUE, m) &&
  1502. X        (sd = AddOption(&gl, 0, "Show discontinuities", TRUE, this->f.showdisc
  1503. X* SELECTED, 0, 9, 100, 10, 10, m)) &&
  1504. X        (nd = AddOption(&gl, 0, "Allow flat discontinuities", TRUE, this->f.nic
  1505. Xedisc * SELECTED, 0, 9, 120, 10, 10, m)) &&
  1506. X        AddBox(&gl, TRUE, "Ok", 0, RELVERIFY | ENDGADGET, 40, 140, 65, 15, FALS
  1507. XE, m) &&
  1508. X        AddBox(&gl, FALSE, "Cancel", 0, RELVERIFY | ENDGADGET, 145, 140, 65, 15
  1509. X, FALSE, m))
  1510. X    {
  1511. X        SetReqGadgets(req, gl);
  1512. X        if (ret = DoRequest(req, this->f.o.g, std_ghandler))
  1513. X        {
  1514. X            *ref = full_refresh(this->f.o.g);
  1515. X
  1516. X            /* Extract info */
  1517. X            this->f.min = str2double(from);
  1518. X            this->f.max = str2double(to);
  1519. X            this->f.steps = str2int(steps);
  1520. X            if ((this->f.colour = str2int(colour)) == INOVAL) this->f.colour =
  1521. X1;
  1522. X            this->f.showdisc = (sd->Flags & SELECTED) != 0;
  1523. X            this->f.nicedisc = (nd->Flags & SELECTED) != 0;
  1524. X            strcpy(this->x, x);
  1525. X            strcpy(this->y, y);
  1526. X            strcpy(this->f.vname, tname);
  1527. X
  1528. X            /* Create function */
  1529. X            destroy_x_y(this);
  1530. X            if (this->f.o.ok = x_y_ok(this)) this->f.o.ok = create_x_y(this);
  1531. X        }
  1532. X    }
  1533. X    Free(m);
  1534. X
  1535. X    return ret;
  1536. X}
  1537. X
  1538. X/* Calculate points of function */
  1539. Xstatic int calc_x_y(struct x_y *this, int allow_mes)
  1540. X{
  1541. X    double t;
  1542. X    int i;
  1543. X    struct graph *const g = this->f.o.g;
  1544. X    double const tmin = this->f.min;
  1545. X    double const tmax = this->f.max;
  1546. X    int const steps = this->f.steps == INOVAL ? DEFSTEPS : this->f.steps;
  1547. X    double const step = (tmax - tmin) / (steps - 1);
  1548. X    static char func[FNAMELEN + 30];
  1549. X
  1550. X    strcpy(func, "Can't calculate points for ");
  1551. X    strcat(func, this->f.o.name);
  1552. X    strcat(func, ":");
  1553. X
  1554. X    new_list(&this->f.pts);
  1555. X
  1556. X    if (!create_quick(&this->f.var))
  1557. X    {
  1558. X        if (allow_mes) message(g, func, "Couldn't create variable", (char *)NUL
  1559. XL);
  1560. X        else alert(g->io.win, func, "Couldn't create variable");
  1561. X        return FALSE;
  1562. X    }
  1563. X
  1564. X    /* Calculate steps points, spread evenly from min to max */
  1565. X    for (i = 0, t = tmin; i < steps; i++, t += step)
  1566. X    {
  1567. X        point_x_y *pt = alloc_node(this->f.sizept);
  1568. X
  1569. X        if (!pt)
  1570. X        { /* No mem */
  1571. X            free_list(&this->f.pts, this->f.sizept);
  1572. X            free_quick(&this->f.var);
  1573. X            if (allow_mes) message(g, func, "No memory", (char *)NULL);
  1574. X            else alert(g->io.win, func, "No memory");
  1575. X            return FALSE;
  1576. X        }
  1577. X        add_tail(&this->f.pts, pt);
  1578. X
  1579. X        set_quick(&this->f.var, t);
  1580. X        pt->t = t;
  1581. X
  1582. X        pt->p.x = quick_eval(this->x_t);
  1583. X        pt->p.state = (eval_error == 0) ? EXISTS : 0;
  1584. X        if (pt->p.state == EXISTS)
  1585. X        {
  1586. X            pt->p.y = quick_eval(this->y_t);
  1587. X            pt->p.state = (eval_error == 0) ? EXISTS : 0;
  1588. X        }
  1589. X    }
  1590. X    free_quick(&this->f.var);
  1591. X    return TRUE;
  1592. X}
  1593. X
  1594. X/* Try to improve look of function by adding points. If fails, decides that
  1595. X   there is a discontinuity */
  1596. X/* see f_of_x.c for details */
  1597. Xstatic int improve_x_y(struct x_y *this)
  1598. X{
  1599. X    struct graph *const g = this->f.o.g;
  1600. X    point_x_y *pt, *next;
  1601. X    int ok = FALSE, iter, abort = FALSE;
  1602. X    double flatx = FLAT * (g->a.y.max - g->a.y.min) / g->io.win->Height;
  1603. X    double flaty = FLAT * (g->a.x.max - g->a.x.min) / g->io.win->Width;
  1604. X    char msg[FNAMELEN + 30];
  1605. X    char pass[20];
  1606. X    struct Requester *req;
  1607. X    struct Region *full = NULL;
  1608. X
  1609. X    /* Flat has no meaning when graph incorrect */
  1610. X    if (!this->f.o.g->ok) flatx = flaty = 0.0;
  1611. X
  1612. X    if (!this->f.calc)
  1613. X    {
  1614. X        strcpy(msg, this->f.o.name);
  1615. X        strcpy(msg, "not calculated!");
  1616. X        message(g, msg, (char *)NULL);
  1617. X        return NULL;
  1618. X    }
  1619. X    if (!this->dx || !this->dy)
  1620. X    {
  1621. X        strcpy(msg, this->f.o.name);
  1622. X        strcat(msg, " wasn't differentiable");
  1623. X        message(g, msg, (char *)NULL);
  1624. X        return NULL;
  1625. X    }
  1626. X    if (!create_quick(&this->f.var))
  1627. X    {
  1628. X        message(g, "Couldn't create variable", (char *)NULL);
  1629. X        return NULL;
  1630. X    }
  1631. X
  1632. X    if (!(req = abort_request(g, "Improve: Pass 1")))
  1633. X        message(g, "No Memory !", (char *)NULL);
  1634. X    else
  1635. X    {
  1636. X        full = full_refresh(this->f.o.g);
  1637. X
  1638. X        for (iter = 1; iter <= MAXITER && !ok && !abort; iter++)
  1639. X        {
  1640. X            sprintf(pass, "Improve: Pass %d", iter);
  1641. X            set_abort_msg(req, pass);
  1642. X            ok = TRUE;
  1643. X
  1644. X            for (pt = first(&this->f.pts); succ(next = succ(pt)); pt = next)
  1645. X            {
  1646. X                if ((pt->p.state & (EXISTS | OK)) == EXISTS) /* Only exists */
  1647. X                {
  1648. X                    double dx, dy;
  1649. X
  1650. X                    pt->p.state |= OK;
  1651. X                    pt->p.state &= ~DISC;
  1652. X
  1653. X                    set_quick(&this->f.var, pt->t);
  1654. X                    dx = quick_eval(this->dx);
  1655. X                    if (eval_error == 0)
  1656. X                    {
  1657. X                        dy = quick_eval(this->dy);
  1658. X                        if (eval_error == 0)
  1659. X                        {
  1660. X                            double ecartx = next->p.x - pt->p.x;
  1661. X                            double errorx = fabs(ecartx - (next->t - pt->t) * d
  1662. Xx);
  1663. X                            double ecarty = next->p.y - pt->p.y;
  1664. X                            double errory = fabs(ecarty - (next->t - pt->t) * d
  1665. Xy);
  1666. X
  1667. X                            /* Check both axes */
  1668. X                            if ((errorx > fabs(ecartx) * MAXERROR && (!this->f.
  1669. Xnicedisc || errorx > flatx)) ||
  1670. X                                (errory > fabs(ecarty) * MAXERROR && (!this->f.
  1671. Xnicedisc || errory > flaty)))
  1672. X                            {
  1673. X                                pt->p.state &= ~OK;
  1674. X                                ok = FALSE;
  1675. X
  1676. X                                if (iter == MAXITER) pt->p.state |= DISC;
  1677. X                                else /* cut interval in 2 */
  1678. X                                {
  1679. X                                    point_x_y *newpt = alloc_node(this->f.sizep
  1680. Xt);
  1681. X
  1682. X                                    if (!newpt)
  1683. X                                    {
  1684. X                                        nomem(g->io.win);
  1685. X                                        abort = TRUE;
  1686. X                                        break;
  1687. X                                    }
  1688. X
  1689. X                                    newpt->t = (pt->t + next->t) / 2;
  1690. X                                    set_quick(&this->f.var, newpt->t);
  1691. X                                    newpt->p.x = quick_eval(this->x_t);
  1692. X                                    newpt->p.state = (eval_error == 0) ? EXISTS
  1693. X : 0;
  1694. X                                    if (newpt->p.state == EXISTS)
  1695. X                                    {
  1696. X                                        newpt->p.y = quick_eval(this->y_t);
  1697. X                                        newpt->p.state = (eval_error == 0) ? EX
  1698. XISTS : 0;
  1699. X                                    }
  1700. X                                    insert(&this->f.pts, newpt, pt);
  1701. X                                }
  1702. X                            }
  1703. X                        }
  1704. X                    }
  1705. X                }
  1706. X            }
  1707. X        }
  1708. X        end_abort_request(req);
  1709. X    }
  1710. X    free_quick(&this->f.var);
  1711. X    return full;
  1712. X}
  1713. X
  1714. X/* String representation of function */
  1715. Xstatic char *f2str_x_y(struct x_y *this, char *buf, int maxlen)
  1716. X{
  1717. X    buf[maxlen - 1] = '\0';
  1718. X    strncpy(buf, this->f.o.name, maxlen - 1);
  1719. X    strncat(buf, ": x(", maxlen - strlen(buf) - 1);
  1720. X    strncat(buf, this->f.vname, maxlen - strlen(buf) - 1);
  1721. X    strncat(buf, ")=", maxlen - strlen(buf) - 1);
  1722. X    strncat(buf, this->x, maxlen - strlen(buf) - 1);
  1723. X    strncat(buf, ", y(", maxlen - strlen(buf) - 1);
  1724. X    strncat(buf, this->f.vname, maxlen - strlen(buf) - 1);
  1725. X    strncat(buf, ")=", maxlen - strlen(buf) - 1);
  1726. X    strncat(buf, this->y, maxlen - strlen(buf) - 1);
  1727. X
  1728. X    return buf;
  1729. X}
  1730. X
  1731. X/* Save local data to file */
  1732. Xstatic int save_x_y(struct x_y *this, FILE *f)
  1733. X{
  1734. X    short tag = X_Y_TAG;
  1735. X    short end = X_Y_END;
  1736. X
  1737. X    return WRITE(f, tag) &&
  1738. X           WRITE(f, this->x) &&
  1739. X           WRITE(f, this->y) &&
  1740. X           WRITE(f, end);
  1741. X}
  1742. X
  1743. X/* free function */
  1744. Xstatic struct Region *delete_x_y(struct x_y *this)
  1745. X{
  1746. X    struct Region *full = full_refresh(this->f.o.g);
  1747. X
  1748. X    destroy_x_y(this);
  1749. X    FreeMem(this, sizeof(struct x_y));
  1750. X
  1751. X    return full;
  1752. X}
  1753. X
  1754. X/* Create a new function */
  1755. Xstruct x_y *new_x_y(struct graph *g, char *name)
  1756. X{
  1757. X    struct x_y *this = AllocMem(sizeof(struct x_y), MEMF_CLEAR);
  1758. X
  1759. X    if (this)
  1760. X    {
  1761. X        /* Standard init */
  1762. X        init_function(&this->f, g, name);
  1763. X        /* Local methods */
  1764. X        this->f.o.delete = (void *)delete_x_y;
  1765. X        this->f.o.edit = (void *)edit_x_y;
  1766. X        this->f.o.improve = (void *)improve_x_y;
  1767. X        this->f.o.f2str = (void *)f2str_x_y;
  1768. X        this->f.calcf = (void *)calc_x_y;
  1769. X        this->f.save = (void *)save_x_y;
  1770. X        this->f.sizept = sizeof(point_x_y);
  1771. X        return this;
  1772. X    }
  1773. X    message(g, "Couldn't create function:", "No memory", (char *)NULL);
  1774. X    return NULL;
  1775. X}
  1776. X
  1777. X/* load from file */
  1778. Xstruct x_y *load_x_y(struct graph *g, FILE *f)
  1779. X{
  1780. X    struct x_y *this = new_x_y(g, "");
  1781. X
  1782. X    if (this)
  1783. X    {
  1784. X        short end;
  1785. X
  1786. X        /* Read local data */
  1787. X        if (READ(f, this->x) &&
  1788. X            READ(f, this->y) &&
  1789. X            READ(f, end) &&
  1790. X            end == X_Y_END)
  1791. X        {
  1792. X            load_rest(&this->f, f); /* Read standard data */
  1793. X            if (this->f.o.ok = x_y_ok(this)) this->f.o.ok = create_x_y(this);
  1794. X
  1795. X            return this;
  1796. X        }
  1797. X        delete_x_y(this);
  1798. X    }
  1799. X    return NULL;
  1800. X}
  1801. X
  1802. SHAR_EOF
  1803. echo "End of archive 7 (of 7)"
  1804. # if you want to concatenate archives, remove anything after this line
  1805. exit
  1806.